﻿using System;
using Mockery.Core;
using NUnit.Framework;
using Rhino.Mocks;

namespace Mockery.UnitTest
{
    [TestFixture]
    public class ArrangerTests
    {
        #region Embedded Test Classes

        public interface IBar
        {
            int Multiplier { get; }
        }



        public class Foo
        {
            private readonly IBar _bar;
            public Foo(IBar bar)
            {
                _bar = bar;
            }

            public int Value()
            {
                return _bar.Multiplier;
            }
        }

        #endregion
        
        [Test]
        public void Arranger_ConstructorErrorTests()
        {
            Assert.That(Assert.Throws<ArgumentNullException>(() => new Arranger(null)).ParamName,
                        Is.EqualTo("arrangement"));
        }
        

        [Test]
        public void Arranger_ExpectOnTest()
        {
            var actualValue = 0;
            const int returnValue = 42;

            InjectedTest.Target<Foo>()
                .Arrange(a => a.AddStrictMock<IBar>()
                               .ExpectOn<IBar>(e=>Expect.Call(e.Multiplier).Return(returnValue)))
                .Act(c => actualValue = c.Value())
                .Assert(() => Assert.That(actualValue, Is.EqualTo(returnValue)));
        }


        [Test]
        public void Arranger_AddDynamicMockTest()
        {
            var mocks = new MockRepository();

            var arrangement = mocks.StrictMock<IArrangement>();
            var fooDependency = mocks.Stub<IFooDependency>();

            mocks.Record();

            Expect.Call(arrangement.AddDynamicMock<IFooDependency>()).Return(fooDependency);

            mocks.ReplayAll();

            var arranger = new Arranger(arrangement);

            Assert.That(arranger.AddDynamicMock<IFooDependency>(), Is.TypeOf<Arranger>());

            mocks.VerifyAll();
        }

        [Test]
        public void Arranger_AddStubTest()
        {
            var mocks = new MockRepository();

            var arrangement = mocks.StrictMock<IArrangement>();
            var fooDependency = mocks.Stub<IFooDependency>();

            mocks.Record();

            Expect.Call(arrangement.AddStub<IFooDependency>()).Return(fooDependency);

            mocks.ReplayAll();

            var arranger = new Arranger(arrangement);

            Assert.That(arranger.AddStub<IFooDependency>(), Is.TypeOf<Arranger>());

            mocks.VerifyAll();
        }

        [Test]
        public void Arranger_AddSingletonTypeTest()
        {
            var mocks = new MockRepository();

            var arrangement = mocks.StrictMock<IArrangement>();
            var fooDependency = mocks.Stub<IFooDependency>();

            mocks.Record();

            Expect.Call(() => arrangement.AddMockedType(fooDependency));

            mocks.ReplayAll();

            var arranger = new Arranger(arrangement);

            Assert.That(arranger.AddSingletonType(fooDependency), Is.TypeOf<Arranger>());

            mocks.VerifyAll();
        }


        [Test]
        public void Arranger_AddStrictMockTest()
        {
            var mocks = new MockRepository();

            var arrangement = mocks.StrictMock<IArrangement>();
            var fooDependency = mocks.Stub<IFooDependency>();

            mocks.Record();

            Expect.Call(arrangement.AddStrictMock<IFooDependency>()).Return(fooDependency);

            mocks.ReplayAll();
            
            var arranger = new Arranger(arrangement);

            Assert.That( arranger.AddStrictMock<IFooDependency>(), Is.TypeOf<Arranger>());

            mocks.VerifyAll();
        }


        [Test]
        public void Arrange_GetMockedValueTests()
        {
            var mocks = new MockRepository();

            var arrangement = mocks.StrictMock<IArrangement>();
            var fooDependency = mocks.Stub<IFooDependency>();

            mocks.Record();

            Expect.Call(arrangement.GetMockedType<IFooDependency>()).Return(fooDependency);

            mocks.ReplayAll();

            var arranger = new Arranger(arrangement);

            Assert.That(arranger.GetMockedValue<IFooDependency>(), Is.Not.Null);

            mocks.VerifyAll();
        }
        
    }
}
